package com.example.scancodelogindemo.controller;

import com.example.scancodelogindemo.enums.QrCodeStatusEnum;
import com.example.scancodelogindemo.model.QrCodeInfo;
import com.example.scancodelogindemo.model.Result;
import com.example.scancodelogindemo.model.vo.QrCodeVO;
import com.example.scancodelogindemo.service.LongPollFactory;
import com.example.scancodelogindemo.service.QrcodeLoginService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;

import javax.servlet.http.HttpServletRequest;


/**
 * qrcode登录控制器
 *
 * @author 傲寒
 * @date 2023/12/6
 */
@Slf4j
@RestController
@RequestMapping("/api/v1/account")
public class QrcodeLoginController {

    private final QrcodeLoginService qrcodeLoginService;

    public QrcodeLoginController(QrcodeLoginService qrcodeLoginService) {
        this.qrcodeLoginService = qrcodeLoginService;
    }

    /**
     * 创建二维码
     *
     * @return {@link Result}<{@link String}>
     */
    @GetMapping("/getQrCode")
    public Result<QrCodeVO> getQrCode() {
        return Result.ok(qrcodeLoginService.createQrCode());
    }

    /**
     * 轮询版本
     * 前端轮训 查询二维码状态
     *
     * @param qrcodeId qrcode id
     * @return {@link Result}<{@link String}>
     */
    @GetMapping("/checkQrState/{qrcodeId}")
    public Result<QrCodeInfo> checkQrState(@PathVariable("qrcodeId") String qrcodeId) {
        return Result.ok(qrcodeLoginService.checkQrState(qrcodeId));
    }

    /**
     * 使用长轮询的方式
     * 检查qr状态v2
     *
     * @param qrcodeId qrcode id
     * @return {@link DeferredResult}<{@link Result}<{@link QrCodeInfo}>>
     */
    @GetMapping("/checkQrStateV2/{qrcodeId}")
    public DeferredResult<Result<QrCodeInfo>> checkQrStateV2(@PathVariable("qrcodeId") String qrcodeId) {
        //初始化DeferredResult 超时时间  和超时后返回什么内容
        final DeferredResult<Result<QrCodeInfo>> deferredResult = new DeferredResult<>(
                20000L,
                () -> Result.ok(qrcodeLoginService.checkQrState(qrcodeId))
        );
        //判断二维码不存在立即返回
        final boolean exists = qrcodeLoginService.getQrCodeInfoBucket(qrcodeId).isExists();
        if (!exists) {
            deferredResult.setResult(Result.ok(new QrCodeInfo(qrcodeId, QrCodeStatusEnum.INVALID)));
        }
        //超时 & 完成 时的操作
        deferredResult.onTimeout(() -> {
            log.info("QrcodeLoginController#checkQrStateV2 调用超时 qrcodeId:{}", qrcodeId);
            LongPollFactory.remove(qrcodeId);
        });
        deferredResult.onCompletion(() -> {
            log.info("QrcodeLoginController#checkQrStateV2 调用完成 qrcodeId:{}", qrcodeId);
            LongPollFactory.remove(qrcodeId);
        });
        //放入长轮询的工程，在状态变化是通知使用
        LongPollFactory.put(qrcodeId, deferredResult);
        return deferredResult;
    }

    /**
     * 扫描
     *
     * @param qrcodeId qrcode id
     * @return {@link Result}<{@link QrCodeInfo}>
     */
    @PostMapping("/scan/{qrcodeId}")
    public Result<Boolean> scan(@PathVariable("qrcodeId") String qrcodeId, HttpServletRequest request) {
        return Result.ok(qrcodeLoginService.scan(qrcodeId, request));
    }

    /**
     * 确认
     *
     * @param qrcodeId qrcode id
     * @param request  请求
     * @return {@link Result}<{@link Void}>
     */
    @PostMapping("/confirm/{qrcodeId}")
    public Result<Void> confirm(@PathVariable("qrcodeId") String qrcodeId, HttpServletRequest request) {
        qrcodeLoginService.confirm(qrcodeId, request);
        return Result.ok();
    }

    /**
     * 取消
     *
     * @param qrcodeId qrcode id
     * @return {@link Result}<{@link Boolean}>
     */
    @PostMapping("/cancel/{qrcodeId}")
    public Result<Void> cancel(@PathVariable("qrcodeId") String qrcodeId) {
        qrcodeLoginService.cancel(qrcodeId);
        return Result.ok();
    }


}
